/*
 * Copyright 2019-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.cdeden.knowledge.utils;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.LongStream;

import static cn.hutool.core.date.DateUtil.rangeToList;

/**
 * @author: liaojinlong
 * @date: 2020/6/11 16:28
 * @apiNote: JDK 8  新日期类 格式化与字符串转换 工具类
 */
@Slf4j
public class DateUtil {

    public static final DateTimeFormatter DFY_MD_HMS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    public static final DateTimeFormatter DFY_MD_HM = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    public static final DateTimeFormatter DFY_MD = DateTimeFormatter.ofPattern("yyyy-MM-dd");


    /**
     * @param dateString
     * @return java.util.Date
     * @Description //  将以要知的数据时间格式进行转换
     * @Date 2024/5/7 17:22
     **/
    public static Date convertStringToDate(String dateString) {
        SimpleDateFormat formatter;
        String[] dateFormats = {
                "yyyy-MM-dd'T'HH:mm:ss.SSS 'Z'",
                "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
                "yyyy-MM-dd'T'HH:mm:ss 'Z'",
                "MM-dd-yyyy HH:mm:ss",
                "MM/dd/yyyy HH:mm:ss",
                "yyyy/MM/dd HH:mm:ss",
                "yyyy-MM-dd HH:mm:ss",
                "yyyy/MM/dd",
                "yyyy-MM-dd"
        };

        for (String format : dateFormats) {
            formatter = new SimpleDateFormat(format, Locale.ENGLISH);
            try {
                return formatter.parse(dateString);
            } catch (ParseException e) {
                // Try the next format
//                e.printStackTrace();


            }
        }

        return null;
    }


    /**
     * @param formatter
     * @return java.lang.String
     * @author Yu.
     * @Description // 获取 当前时间的某个格式的
     * @Date 2023/1/18 11:21
     **/
    public static String getTime(DateTimeFormatter formatter) {
        LocalDateTime now = LocalDateTime.now();
        return localDateTimeFormaty(now, formatter);
    }

    /**
     * @return java.lang.String
     * @author Yu.
     * @Description // 获取 当前时间的格式的  yyyy-MM-dd HH:mm:ss
     * @Date 2023/1/18 11:21
     **/
    public static String getTimeHms() {
        return localDateTimeFormaty(LocalDateTime.now(), DFY_MD_HMS);
    }

    /**
     * @return java.lang.String
     * @author Yu.
     * @Description // 获取 当前时间格式的  yyyy-MM-dd
     * @Date 2023/1/18 11:21
     **/
    public static String getTimeMd() {
        return localDateTimeFormaty(LocalDateTime.now(), DFY_MD);
    }


//    public static String localDateTimeFormatyMd(LocalDateTime localDateTime) {
//        return DFY_MD.format(localDateTime);
//    }


    /**
     * LocalDateTime 转时间戳(秒)
     *
     * @param localDateTime /
     * @return /
     */
    public static Long getTimeStamp(LocalDateTime localDateTime) {
        return localDateTime.atZone(ZoneId.systemDefault()).toEpochSecond();
    }

    /**
     * LocalDateTime 转时间戳(毫秒)
     *
     * @param localDateTime /
     * @return /
     */
    public static Long getTimeStampMs(LocalDateTime localDateTime) {
        return localDateTime.atZone(ZoneId.systemDefault()).toEpochSecond() * 1000;
    }

    /**
     * 时间戳转LocalDateTime
     *
     * @param timeStamp /
     * @return /
     */
    public static LocalDateTime fromTimeStamp(Long timeStamp) {
        return LocalDateTime.ofEpochSecond(timeStamp, 0, OffsetDateTime.now().getOffset());
    }

    /**
     * LocalDateTime 转 Date
     * Jdk8 后 不推荐使用 {@link Date} Date
     *
     * @param localDateTime /
     * @return /
     */
    public static Date toDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * LocalDate 转 Date
     * Jdk8 后 不推荐使用 {@link Date} Date
     *
     * @param localDate /
     * @return /
     */
    public static Date toDate(LocalDate localDate) {
        return toDate(localDate.atTime(LocalTime.now(ZoneId.systemDefault())));
    }


    /**
     * Date转 LocalDateTime
     * Jdk8 后 不推荐使用 {@link Date} Date
     *
     * @param date /
     * @return /
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    /**
     * 日期 格式化
     *
     * @param localDateTime /
     * @param patten        /
     * @return /
     */
    public static String localDateTimeFormat(LocalDateTime localDateTime, String patten) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(patten);
        return df.format(localDateTime);
    }

    /**
     * 日期 格式化
     *
     * @param localDateTime /
     * @param df            /
     * @return /
     */
    public static String localDateTimeFormat(LocalDateTime localDateTime, DateTimeFormatter df) {
        return df.format(localDateTime);
    }

    /**
     * 日期格式化 yyyy-MM-dd HH:mm:ss
     *
     * @param localDateTime /
     * @return /
     */
    public static String localDateTimeFormatyMdHms(LocalDateTime localDateTime) {
        return DFY_MD_HMS.format(localDateTime);
    }

    public static String dateTimeFormatyMdHms(Date localDateTime) {
//        return DFY_MD_HMS.format(localDateTime);
        return null;
    }


    /**
     * 日期格式化 yyyy-MM-dd
     *
     * @param localDateTime /
     * @return /
     */
    public static String localDateTimeFormatyMd(LocalDateTime localDateTime) {
        return DFY_MD.format(localDateTime);
    }


    public static String localDateTimeFormaty(LocalDateTime localDateTime, DateTimeFormatter formatter) {
        return formatter.format(localDateTime);
    }


    /**
     * 字符串转 LocalDateTime ，字符串格式 yyyy-MM-dd
     *
     * @param localDateTime /
     * @return /
     */
    public static LocalDateTime parseLocalDateTimeFormat(String localDateTime, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDateTime.from(dateTimeFormatter.parse(localDateTime));
    }

    /**
     * 字符串转 localDate ，字符串格式 yyyy-MM-dd
     *
     * @param localDate /
     * @return /
     */
    public static LocalDate parseLocalDateFormatYMD(String localDate) {
        return LocalDate.from(DFY_MD.parse(localDate)); // 将字符串转换为LocalDate对象
    }

    /**
     * 字符串转 LocalDateTime ，字符串格式 yyyy-MM-dd HH:mm:ss
     *
     * @param localDateTime /
     * @return /
     */
    public static LocalDateTime parseLocalDateTimeFormatyMdHms(String localDateTime) {
        return LocalDateTime.from(DFY_MD_HMS.parse(localDateTime));
    }

    /**
     * @param date
     * @param amount 秒
     * @return java.util.Date
     * @author Yu.
     * @Description // 增加时间
     * @Date 2023/2/8 15:37
     **/
    public static Date dateAddOne(Date date, Integer amount) {
        if (amount == null) {
            amount = 1;
        }
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.SECOND, amount); //把日期往后增加一秒,整数  往后推,负数往前移动
        date = calendar.getTime(); //这个时间就是日期往后推一秒的结果
        return date;
    }

    /**
     * @param date
     * @param amount
     * @param type   年还是月
     * @return java.util.Date
     * @author Yu.
     * @Description // TODO
     * @Date 2023/2/8 16:20
     **/
    public static Date dateAddOne(Date date, Integer amount, int type) {
        if (amount == null) {
            amount = 1;
        }
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(type, amount); //把日期往后增加一秒,整数  往后推,负数往前移动
        date = calendar.getTime(); //这个时间就是日期往后推一秒的结果
        return date;
    }


    /**
     * @param date
     * @param amount
     * @return java.util.Date
     * @author Yu.
     * @Description // 时间 反
     * @Date 2023/2/8 15:37
     **/
    public static Date dateDelOne(Date date, Integer amount) {
        if (amount == null) {
            amount = 1;
        }
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.SECOND, (~(amount - 1))); //把日期往后增加一秒,整数  往后推,负数往前移动
//        calendar.set(Calendar.SECOND,amount); //把日期往后增加一秒,整数  往后推,负数往前移动
        date = calendar.getTime(); //这个时间就是日期往后推一秒的结果
        return date;

    }

    public static Long daysBetween(String begDate, String endDate) {
        return daysBetween(begDate,begDate,0);
    }

    public static Long daysBetween(String begDate, String endDate, int day) {
        LocalDate begLocalDate = parseLocalDateFormatYMD(begDate);
        LocalDate endLocalDate = parseLocalDateFormatYMD(endDate);
        long daysBetween = ChronoUnit.DAYS.between(begLocalDate, endLocalDate);
        return daysBetween + day;
    }


    /**
     * @param lastTime //开始的时间
     * @param endTime  //结束的时间
     * @return boolean
     * @author Yu.
     * @Description //  判断相差的时间 毫秒
     * @Date 2022/6/22 11:18
     **/
    public static int judgeDifferenceTime(Date lastTime, Date endTime) {
        long from2 = lastTime.getTime();
        long to2 = endTime.getTime();
        int hours = (int) ((to2 - from2) / (1));
        return hours;
    }


    /**
     * @param lastTime //开始的时间
     * @param endTime  //结束的时间
     * @return boolean
     * @author Yu.
     * @Description //  判断相差的多少天
     * @Date 2022/6/22 11:18
     **/
    public static int judgeDifferenceDay(Date lastTime, Date endTime) {
        long from2 = lastTime.getTime();
        long to2 = endTime.getTime();
        int hours = (int) ((to2 - from2) / (1000 * 60 * 60 * 24));
        return hours;
    }


    /**
     * @param lastTime //开始的时间
     * @param endTime  //结束的时间
     * @return boolean
     * @author Yu.
     * @Description //  是否大于
     * @Date 2022/6/22 11:18
     **/
    public static boolean judgeDifference(Date lastTime, Date endTime) {
        return lastTime.getTime() > endTime.getTime();
    }

    public static String getThisWeekOfMonday() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        // 获得当前日期是一个星期的第几天 使用cal.get(Calendar.DAY_OF_WEEK);
        // 获取的数表示的是每个星期的第几天，不能改变，其中星期日为第一天
        // 如果是星期日则获取天数时获取到的数字为1 在后面进行相减的时候出错
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (1 == dayWeek) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
        }
        // 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        // 获得当前日期是一个星期的第几天
        int day = cal.get(Calendar.DAY_OF_WEEK);
        // 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        //  cal.getFirstDayOfWeek()根据前面的设置 来动态的改变此值
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day);
        return cal.get(Calendar.YEAR) + "/" + (cal.get(Calendar.MONTH) + 1) + "/" + cal.get(Calendar.DATE);
    }

    public static String getLastWeekOfMonday() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date(getThisWeekOfMonday()));
        cal.add(Calendar.DATE, -7);
        return cal.get(Calendar.YEAR) + "/" + (cal.get(Calendar.MONTH) + 1) + "/" + cal.get(Calendar.DATE);
    }

    /**
     * @param format
     * @param date
     * @return java.lang.String
     * @Description // 将时间类转成固定的 时间格式字符串
     * @Date 2024/5/7 17:24
     **/
    public static final String parseDateToStr(final DateTimeFormatter format, final Date date) {
        // 将时间类转成固定的 时间格式
        LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        return format.format(localDateTime);
    }

    /**
     * @param format 日期时间格式化
     * @param date   需要转换的日期对象
     * @return java.lang.String
     * @Description // 将时间类转成固定的 时间格式字符串
     * @Date 2024/5/7 17:24
     **/
    public static final String parseDateToStr(final String format, final Date date) {
        return new SimpleDateFormat(format).format(date);
    }


    /**
     * 得到当天开始时间
     *
     * @return
     */
    public static Date getStartDay() {
        Calendar calendar = Calendar.getInstance();
        setStartHMS(calendar);
        return calendar.getTime();
    }

    /**
     * 得到当天结束时间
     *
     * @return
     */
    public static Date getEndDay() {
        Calendar calendar = Calendar.getInstance();
        setEndHMS(calendar);
        return calendar.getTime();
    }

    /**
     * 周
     */
    public static Date getWeeklyStart() {
        Calendar calendar = Calendar.getInstance();

        // 如果是周日
        if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
            calendar.add(Calendar.DAY_OF_YEAR, -1);
        }

        // 获取当前日期是当周的第i天
        int i = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        // 获取当前日期所在周的第一天
        calendar.add(Calendar.DATE, -i + 1);
        return setStartHMS(calendar);
    }

    public static Date getWeeklyEnd() {
        Calendar calendar = Calendar.getInstance();
        // 如果是周日
        if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
            calendar.add(Calendar.DAY_OF_YEAR, -1);
        }
        // 获取当前日期是当周的第i天
        int i = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        // 获取当前日期所在周的第一天
        calendar.add(Calendar.DATE, -i + 1);
        calendar.add(Calendar.DATE, 6);
        return setEndHMS(calendar);
    }




    /**
     * 获取这个月的所有日期列表。
     *
     * @return 获取这个月的所有日期列表
     */
    public static List<Date> getMonthDays() {

        return getDateList(new Date());
    }

    /**
     * 获取上个月的所有日期列表。
     *
     * @return 上个月的所有日期列表
     */
    public static List<Date> getPrevMonthDays() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.MONTH, -1);
        return getDateList(calendar.getTime());

    }


    /**
     * 获取当前月份的第一天日期。
     * 该方法不接受任何参数。
     *
     * @return 返回设置好时分秒的当前月份最后一天的Date对象。
     */
    public static Date getMonthlyStart() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return setStartHMS(calendar);
    }



    /**
     * 获取当前月份的最后一天日期。
     * 该方法不接受任何参数。
     *
     * @return 返回设置好时分秒的当前月份最后一天的Date对象。
     */
    public static Date getMonthlyEnd() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.roll(Calendar.DAY_OF_MONTH, -1);
        return setEndHMS(calendar);
    }
    /**
     * 得到下月开始时间
     */
    public static Date getLowerMonthStart() {
        Calendar calendar = Calendar.getInstance();// 获取当前日期
        calendar.add(Calendar.YEAR, 0);
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);// 设置为1号,当前日期既为本月第一天    }
        return setStartHMS(calendar);
    }

    public static Date getLowerMonthEnd() {
        Calendar calendar = Calendar.getInstance();// 获取当前日期
        calendar.add(Calendar.YEAR, 0);
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));// 获取当前月最后一天
        return setEndHMS(calendar);
    }
    /**
     * 得到本月开始时间
     */
    public static Date getMonthStart() {
        Calendar calendar = Calendar.getInstance();// 获取当前日期
        calendar.add(Calendar.YEAR, 0);
        calendar.add(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);// 设置为1号,当前日期既为本月第一天
        return setStartHMS(calendar);
    }


    /**
     * 得到上月开始时间
     */
    public static Date getLastMonthStart() {
        Calendar calendar = Calendar.getInstance();// 获取当前日期
        calendar.add(Calendar.YEAR, 0);
        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);// 设置为1号,当前日期既为本月第一天
        return setStartHMS(calendar);
    }

    /**
     * 得到上月结束时间
     */
    public static Date getLastMonthEnd() {
        Calendar calendar = Calendar.getInstance();// 获取当前日期
        calendar.add(Calendar.YEAR, 0);
        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));// 获取当前月最后一天
        return setEndHMS(calendar);
    }

    /**
     * 获取最近的一个月份的日期。
     * 该方法不接受任何参数。
     *
     * @return Date 返回当前日期减去一个月后的日期对象。
     */
    public static Date getRecentlyMonth() {
        Calendar calendar = Calendar.getInstance();// 获取当前日期
        calendar.add(Calendar.MONTH, -1);
        return calendar.getTime();
    }


    /**
     * 季
     */
    public static Date getQuarterlyStart() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.MONTH, (((int) calendar.get(Calendar.MONTH)) / 3) * 3);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return setStartHMS(calendar);
    }

    public static Date getQuarterlyEnd() {
        Calendar calendar = Calendar.getInstance();
        //计算季度数：由于月份从0开始，即1月份的Calendar.MONTH值为0,所以计算季度的第三个月份只需 月份 / 3 * 3 + 2
        calendar.set(Calendar.MONTH, (((int) calendar.get(Calendar.MONTH)) / 3) * 3 + 2);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        return setEndHMS(calendar);
    }


    /**
     * 年
     */
    public static Date getYearStart() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return setStartHMS(calendar);
    }

    /**
     * 获取本年的结束日期，设置为12月30日。该方法不接受任何参数。
     *
     * @return 返回一个Date对象，表示本年的最后一天。
     */
    public static Date getYearEnd() {
        Calendar calendar = Calendar.getInstance();
        //计算季度数：由于月份从0开始，即1月份的Calendar.MONTH值为0,所以计算季度的第三个月份只需 月份 / 3 * 3 + 2
        calendar.set(Calendar.MONTH, 12);
        calendar.set(Calendar.DAY_OF_MONTH, 30);
        return setEndHMS(calendar);
    }


    /**
     * 将指定的Date对象的时间设置为当天的凌晨，即小时、分钟、秒和毫秒都设置为0。
     *
     * @param date 需要被修改的date对象。
     * @return 返回修改后的date对象对应的时间，类型为Date。
     */
    public static Date toDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return setStartHMS(calendar);
    }


    /**
     * 将指定的Calendar对象的时间设置为当天的凌晨，即小时、分钟、秒和毫秒都设置为0。
     *
     * @param calendar 需要被修改的Calendar对象。
     * @return 返回修改后的Calendar对象对应的时间，类型为Date。
     */
    public static Date setStartHMS(Calendar calendar) {
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    public static Date setEndHMS(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return setEndHMS(calendar);
    }

    /**
     * 将指定的 Calendar 对象的时间设置为一天中的最后时刻（23:59:59.999）。
     *
     * @param calendar 待修改的 Calendar 对象。
     * @return 修改后的 Calendar 对象对应的时间，类型为 Date。
     */
    public static Date setEndHMS(Calendar calendar) {
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 59);
        return calendar.getTime();
    }

    /**
     * 获取从今年年初到现在的每个月的起始日期时间对象列表。
     *
     * @return List<DateTime> 返回一个包含从今年年初到当前月份的每个月份起始日期时间对象的列表。
     */
    public static List<DateTime> getMonthsUtilNow() {
        Calendar calendar = Calendar.getInstance();
        Date end = setEndHMS(calendar);
        calendar.set(Calendar.MONTH, 0);
        calendar.set(Calendar.DATE, 1);
        Date start = setStartHMS(calendar);
        return rangeToList(start, end, DateField.MONTH);
    }

    /**
     * 获取最近一周的日期时间列表。
     * 该方法不接受任何参数。
     *
     * @return List<DateTime> 返回一个包含从当前日期往前推8天到今天的日期时间列表。
     */
    public static List<DateTime> getNearWeekDays() {
        Calendar calendar = Calendar.getInstance();
        Date end = setStartHMS(calendar);
        calendar.add(Calendar.DAY_OF_MONTH, -8);
        Date start = setEndHMS(calendar);
        return rangeToList(start, end, DateField.DAY_OF_MONTH);
    }

    // 获取本周的日期时间列表。
    // 该方法不接受任何参数。
    public static List<Date> getWeekDays() {
//        Date now = new Date();
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR); // 获取年份
        int weekOfYear = calendar.get(Calendar.WEEK_OF_YEAR); // 获取当前周是年份中的第几周
        List<Date> weekStartAndEnd = getWeekStartAndEnd(year, weekOfYear);
        return weekStartAndEnd;
    }

    /**
     * @param
     * @return java.util.List<java.util.Date>
     * @author Yu.
     * @Description // 上周日期
     * @Date 2024/8/27 18:00
     **/
    public static List<Date> getPrevWeek() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, -7);
        int year = calendar.get(Calendar.YEAR); // 获取年份
        int weekOfYear = calendar.get(Calendar.WEEK_OF_YEAR); // 获取当前周是年份中的第几周
        List<Date> weekStartAndEnd = getWeekStartAndEnd(year, weekOfYear);
        return weekStartAndEnd;
    }


    /**
     * @param months
     * @return java.util.List<java.util.Date>
     * @author Yu.
     * @Description // 获取月份的时间列表
     * @Date 2024/8/22 9:13
     **/
    public static List<Date> getDateList(Date months) {
        List<Date> dateList = new ArrayList<>();

        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(months);

            // 从第一天开始遍历到当月最后一天
            for (int day = 1; day <= calendar.getActualMaximum(Calendar.DAY_OF_MONTH); day++) {
                calendar.set(Calendar.DAY_OF_MONTH, day);
                dateList.add(new Date(calendar.getTimeInMillis()));
            }

        } catch (Exception e) {
            // 处理异常
            System.err.println("错误处理日期: " + e.getMessage());
            return new ArrayList<>(); // 返回空列表
        }

        return dateList;
    }


    public static List<String> getDateListToStr(Date months) {
        List<String> dateList = new ArrayList<>();

        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(months);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            // 从第一天开始遍历到当月最后一天
            for (int day = 1; day <= calendar.getActualMaximum(Calendar.DAY_OF_MONTH); day++) {
                calendar.set(Calendar.DAY_OF_MONTH, day);
                String dateStr = sdf.format(calendar.getTime());
                dateList.add(dateStr);
            }

        } catch (Exception e) {
            // 处理异常
            System.err.println("错误处理日期: " + e.getMessage());
            return new ArrayList<>(); // 返回空列表
        }

        return dateList;
    }


    /**
     * @param startTime
     * @param endTime
     * @return java.util.List<java.util.Date>
     * @author Yu.
     * @Description // 获取日期列表
     * @Date 2024/7/8 15:22
     **/
    public static List<Date> getDateList(Date startTime, Date endTime) {
        // 检查参数的有效性
        if (startTime.after(endTime)) {
            // 如果开始日期晚于结束日期，返回空列表
            return new ArrayList<>();
        }
        // 将java.util.Date转换为java.time.LocalDate
        LocalDate startLocalDate = startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate endLocalDate = endTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        // 计算日期之间的天数差
        long daysBetween = ChronoUnit.DAYS.between(startLocalDate, endLocalDate);
        // 创建并填充日期列表
//        List<Date> dateList = new ArrayList<>((int)daysBetween);
        List<Date> dateList = new ArrayList<>();
        LocalDate current = startLocalDate;
        for (long i = 0; i <= daysBetween; i++) {
            // 将LocalDate转换回java.util.Date
            Date date = Date.from(current.atStartOfDay(ZoneId.systemDefault()).toInstant());
            dateList.add(date);
            current = current.plusDays(1);
        }
        return dateList;
    }

    public static Map<String, List<Date>> groupedBy(Date startTime, Date endTime) {
        int i = judgeDifferenceDay(startTime, endTime);
        if (i < 30) {
            return groupedByDay(startTime, endTime);
        } else if (i < 365) {
            return groupedByMonth(startTime, endTime);
        } else {
            return groupedByYear(startTime, endTime);
        }
    }


    /**
     * @param startTime
     * @param endTime
     * @return java.util.Map<java.lang.String, java.util.List < java.util.Date>>
     * @author Yu.
     * @Description // 按天分组
     * @Date 2024/8/28 16:32
     **/
    public static Map<String, List<Date>> groupedByDay(Date startTime, Date endTime) {
        LocalDate startDate = startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate endDate = endTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        // 按天分组
        Map<String, List<Date>> groupedByDay = new HashMap<>();
        LocalDate currentDay = startDate;
        while (currentDay.isBefore(endDate) || currentDay.isEqual(endDate)) {
            Date date = Date.from(currentDay.atStartOfDay(ZoneId.systemDefault()).toInstant());
            groupedByDay.put(currentDay.toString(), Arrays.asList(date));
            currentDay = currentDay.plusDays(1);
        }
        return groupedByDay;
    }


    /**
     * @param startTime
     * @param endTime
     * @return java.util.Map<java.lang.String, java.util.List < java.util.Date>>
     * @author Yu.
     * @Description // 按周分组
     * @Date 2024/8/28 17:33
     **/
    public static Map<String, List<Date>> groupedByWeek(Date startTime, Date endTime) {
        LocalDate startDate = startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate endDate = endTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        // 按月份分组
        DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM");
        Map<String, List<Date>> groupedByMonth = new HashMap<>();
        LocalDate currentMonth = startDate.withDayOfMonth(1); // 从开始时间的月份的第一天开始


        while (currentMonth.isBefore(endDate) || currentMonth.isEqual(endDate)) {
            String month = currentMonth.format(monthFormatter);
            // 获取这个月的第一天和最后一天
            LocalDate firstDayOfMonth = currentMonth.with(TemporalAdjusters.firstDayOfMonth());
            LocalDate lastDayOfMonth = currentMonth.with(TemporalAdjusters.lastDayOfMonth());

            // 当前处理的日期
            LocalDate current = firstDayOfMonth;


            // 遍历每一天，直到超出当月最后一天
            int monthWeek = 0;
            while (!current.isAfter(lastDayOfMonth)) {
                List<Date> week = new ArrayList<>();
                // 当前周的天数
                while (current.getDayOfWeek() != DayOfWeek.SUNDAY && !current.isAfter(lastDayOfMonth)) {
                    week.add(Date.from(current.atStartOfDay(ZoneId.systemDefault()).toInstant()));
                    current = current.plusDays(1);
                }
                // 添加周日
                if (current.getDayOfWeek() == DayOfWeek.SUNDAY && !current.isAfter(lastDayOfMonth)) {
                    week.add(Date.from(current.atStartOfDay(ZoneId.systemDefault()).toInstant()));
                    current = current.plusDays(1);
                }

                groupedByMonth.put(month + "-第" + (++monthWeek) + "周", week);
            }
            currentMonth = currentMonth.plusMonths(1);
        }

        return groupedByMonth;
    }


    /**
     * @param startTime
     * @param endTime
     * @return java.util.Map<java.lang.String, java.util.List < java.util.Date>>
     * @author Yu.
     * @Description // 按月分组
     * @Date 2024/8/28 16:34
     **/
    public static Map<String, List<Date>> groupedByMonth(Date startTime, Date endTime) {
        LocalDate startDate = startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate endDate = endTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        // 按月份分组
        DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM");
        Map<String, List<Date>> groupedByMonth = new HashMap<>();
        LocalDate currentMonth = startDate.withDayOfMonth(1); // 从开始时间的月份的第一天开始
        while (currentMonth.isBefore(endDate) || currentMonth.isEqual(endDate)) {
            String month = currentMonth.format(monthFormatter);
            // 获取这个月的第一天和最后一天
            LocalDate firstDayOfMonth = currentMonth.with(TemporalAdjusters.firstDayOfMonth());
            LocalDate lastDayOfMonth = currentMonth.with(TemporalAdjusters.lastDayOfMonth());
//            String period = month + ": " + currentMonth + " to " + currentMonth.with(TemporalAdjusters.lastDayOfMonth());
//            groupedByMonth.add(period);
            groupedByMonth.put(month, getDateList(
                    Date.from(firstDayOfMonth.atStartOfDay(ZoneId.systemDefault()).toInstant()),
                    Date.from(lastDayOfMonth.atStartOfDay(ZoneId.systemDefault()).toInstant()))
            );
            currentMonth = currentMonth.plusMonths(1);
        }

        return groupedByMonth;
    }


    /**
     * @param startTime
     * @param endTime
     * @return java.util.Map<java.lang.String, java.util.List < java.util.Date>>
     * @author Yu.
     * @Description //  按年分组
     * @Date 2024/8/28 17:11
     **/
    public static Map<String, List<Date>> groupedByYear(Date startTime, Date endTime) {
        LocalDate startDate = startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate endDate = endTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        // 按年份分组
        DateTimeFormatter yearFormatter = DateTimeFormatter.ofPattern("yyyy");
        Map<String, List<Date>> groupedByYear = new HashMap<>();
        LocalDate currentYear = startDate.with(TemporalAdjusters.firstDayOfYear()); // 从开始时间的年份的第一天开始
        while (currentYear.isBefore(endDate) || currentYear.isEqual(endDate)) {
            String year = currentYear.format(yearFormatter);
            LocalDate with = currentYear.with(TemporalAdjusters.lastDayOfYear());
            groupedByYear.put(year, getDateList(
                            Date.from(currentYear.atStartOfDay(ZoneId.systemDefault()).toInstant()),
                            Date.from(with.atStartOfDay(ZoneId.systemDefault()).toInstant())
                    )
            );
            currentYear = currentYear.plusYears(1);
        }

        return groupedByYear;

    }


    private static final Set<Integer> WORKDAYS = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5)); // 默认周一到周五是工作日 //后期可以修改为动态的
    private static final Set<Integer> WORKDAYS_ALl = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7)); // 默认周一到周五是工作日 //后期可以修改为动态的
    // 如果需要，你可以在这里添加或修改工作日，例如：WORKDAYS.add(6); 添加周六为工作日


    /**
     * 计算两个日期之间的工日数量（星期一至星期五）。
     *
     * @param startDateStr 开始日期的字符串，格式为"yyyy-MM-dd"
     * @param endDateStr   结束日期的字符串，格式为"yyyy-MM-dd"
     * @return 两个日期之间的工日数量
     */

    public static long getWorkdaysBetween(String startDateStr, String endDateStr) {
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            LocalDate startDate = LocalDate.parse(startDateStr, formatter);
            LocalDate endDate = LocalDate.parse(endDateStr, formatter);
            return getWorkdaysBetween(startDate, endDate, WORKDAYS_ALl);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }

    }

    /**
     * 计算两个日期之间的工作日数量。
     * 工作日由传入的set集合定义，集合包含每个工作日的星期几（1-7，1为星期一，7为星期日）。
     *
     * @param startDate 开始日期，包含此日期本身。
     * @param endDate   结束日期，包含此日期本身。
     * @param workdays  一个整数集，表示每个工作日的星期几。
     * @return 两个日期之间的工作日数量。
     */
    public static long getWorkdaysBetween(final LocalDate startDate, final LocalDate endDate, Set<Integer> workdays) {
        try {
            final LocalDate startDate1, endDate2;
            if (startDate.isAfter(endDate)) {
                startDate1 = endDate;
                endDate2 = startDate;
            } else {
                startDate1 = startDate;
                endDate2 = endDate;
            }

            long daysBetween = (endDate2.toEpochDay() - startDate1.toEpochDay());
            // 计算两个日期之间的天数
//        long daysBetween = startDate.until(endDate.plusDays(1)).getDays();
//            log.info("daysBetween:{}",daysBetween);
            return LongStream.rangeClosed(0, daysBetween)
                    .mapToObj(i -> startDate1.plusDays(i))
                    .filter(d -> workdays.contains(d.getDayOfWeek().getValue()))
                    .count();
        } catch (Exception e) {
            return 0;
        }
    }

    public static List<String> getWeekStartAndEndToStr(Integer year, Integer week) {
        return getWeekStartAndEndToStr(year, week, "yyyy-MM-dd");
    }


    /**
     * @param year
     * @param week
     * @return java.util.List<java.lang.String>
     * @author Yu.
     * @Description // 获取某年第几周开始开始到结束的日期
     * @Date 2024/8/20 10:00
     **/
    public static List<String> getWeekStartAndEndToStr(Integer year, Integer week, String format) {
        // 确保周数在有效范围内
        int maxWeeksInYear = getMaxWeeksInYear(year);
        if (week > maxWeeksInYear) {
            week = maxWeeksInYear;
        }
        // 计算该年的第一天
        LocalDate firstDayOfYear = LocalDate.of(year, 1, 1);
        // 确定该年的第一周开始日期
        LocalDate firstMondayOfYear = firstDayOfYear.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));

        // 计算目标周的开始日期
        LocalDate startOfWeek = firstMondayOfYear.plusWeeks(week - 1);

        // 定义一个DateTimeFormatter对象，指定日期格式为"yyyy-MM-dd"
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        // 返回结果
        List<String> dateList = new ArrayList<>();
        LocalDate current = startOfWeek;
        for (long i = 0; i <= 6; i++) {
            // 将LocalDate转换回java.util.Date
            String date = formatter.format(current);
            dateList.add(date);
            current = current.plusDays(1);
        }
        return dateList;
    }

    public static List<Date> getWeekStartAndEnd(Integer year, Integer week) {
        // 确保周数在有效范围内
        int maxWeeksInYear = getMaxWeeksInYear(year);
        if (week > maxWeeksInYear) {
            week = maxWeeksInYear;
        }
        // 计算该年的第一天
        LocalDateTime dateTime = LocalDateTime.of(year, 1, 1, 0, 0);
        // 确定该年的第一周开始日期
        LocalDateTime firstMondayOfYear = dateTime.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));
        //计算目标周的开始日期
        LocalDateTime localDateTime = firstMondayOfYear.plusWeeks(week - 1);

        // 返回结果
        List<Date> dateList = new ArrayList<>();
        LocalDateTime current = localDateTime;
        for (long i = 0; i <= 6; i++) {
            // 将LocalDate转换回java.util.Date
            Date date = Date.from(current.atZone(ZoneId.systemDefault()).toInstant());
            dateList.add(date);
            current = current.plusDays(1);
        }
        return dateList;
    }


    private static int getMaxWeeksInYear(Integer year) {
        int daysInYear = Year.isLeap(year) ? 366 : 365;
        LocalDate lastDayOfYear = LocalDate.ofYearDay(year, daysInYear);
        LocalDate lastMondayOfYear = lastDayOfYear.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        return lastDayOfYear.equals(lastMondayOfYear) ? 53 : 52;
    }


    public static void main(String[] args) {
//        LocalDate startDate = LocalDate.of(2023, 1, 15);
//        LocalDate endDate = LocalDate.of(2023, 12, 15);
//
//
//        List<Date> dateList = getDateList(new Date(), new Date());
        Date monthlyEnd = getLowerMonthEnd();
        System.out.println(parseDateToStr("yyyy-MM-dd HH:mm:ss",monthlyEnd));
        Date monthlyStart = getLowerMonthStart();
        System.out.println(parseDateToStr("yyyy-MM-dd HH:mm:ss",monthlyStart));



//        getDateGroupedBy(startDate,endDate);
//        List<Date> dateList = getDateList(new Date());
//        List<Date> dateList = getWeekDays();
//        dateList.forEach(System.err::println);
//        List<String> weekStartAndEnd = getWeekStartAndEnd(2022, 50);
//        weekStartAndEnd.forEach(System.err::println);
    }

    /**
     * 获取任意月的起始时间
     * @param today
     * @param number
     * @return
     */
    public static Date getDateByBeforeMonth(Date today, int number) {
        Calendar todayEnd = Calendar.getInstance();
        todayEnd.setTime(today);
        todayEnd.set(Calendar.MONTH, todayEnd.get(Calendar.MONTH) - number);
        todayEnd.set(Calendar.DAY_OF_MONTH, 1);
        todayEnd.set(Calendar.HOUR_OF_DAY, 0);
        todayEnd.set(Calendar.MINUTE, 0);
        todayEnd.set(Calendar.SECOND, 0);
        todayEnd.set(Calendar.MILLISECOND, 0);
        return todayEnd.getTime();
    }

    /**
     * 获取任意月的结束时间
     * @param today
     * @param number
     * @return
     */
    public static Date getDateByAfterMonthNew(Date today, int number) {
        Calendar todayEnd = Calendar.getInstance();
        todayEnd.setTime(today);
        todayEnd.set(Calendar.MONTH, todayEnd.get(Calendar.MONTH)-number);
        todayEnd.set(Calendar.DAY_OF_MONTH, 0);
        todayEnd.set(Calendar.HOUR_OF_DAY, 23);
        todayEnd.set(Calendar.MINUTE, 59);
        todayEnd.set(Calendar.SECOND, 59);
        todayEnd.set(Calendar.MILLISECOND, 999);
        return todayEnd.getTime();
    }

}
